import java.awt.*;
import java.awt.event.*;

import java.util.Locale;
import java.util.ResourceBundle;

import javax.swing.*;
import javax.swing.table.*;

public class Test extends JFrame {
   public static void main(String args[]) {
      SwingApp.launch(new Test(), "A Sort Decorator", 
                                   300, 300, 450, 250);
   }
   public Test() {
      // Create the decorator that will decorate the table's 
      // original model. The reference must be final because it's
      // accessed by an inner class below. Notice that the 
      // reference is TableSortDecorator even though it
      // actually points to a TableBubbleSortDecorator--that
      // way, the mouse listener below will work with any type
      // of TableSortDecorator.
      final TableSortDecorator decorator = 
            new TableBubbleSortDecorator(table.getModel());

      // Set the table's model to the decorator. Because the
      // decorator implements TableModel, the table will never
      // know the difference between the decorator and it's
      // original model.
      table.setModel(decorator);

      // Add a scroll pane around the table, and add the table
      // the content pane:
      getContentPane().add(new JScrollPane(table),
                                BorderLayout.CENTER);

      // Add a status area to this frame:
      getContentPane().add(SwingApp.getStatusArea(),
                                BorderLayout.SOUTH);

      SwingApp.showStatus("Nothing Sorted Originally");

      // Obtain a reference to the table's header
      JTableHeader hdr = (JTableHeader)table.getTableHeader();

      // React to mouse clicks in the table header by calling 
      // the decorator's sort method.
      hdr.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent e) {
            TableColumnModel tcm = table.getColumnModel();
            int vc = tcm.getColumnIndexAtX(e.getX());
            int mc = table.convertColumnIndexToModel(vc);

            // Perform the sort
            decorator.sort(mc);

            // Update the status area
            SwingApp.showStatus(headers[mc] + " sorted");
         }
      });
   }
   final String[] headers = { "Item", "Price/Lb." };
   JTable table = new JTable(new Object[][] {
            {"apple",      "$.39"},  {"mango",      "$.49"},
            {"papaya",     "$1.19"}, {"lemon",      "$.19"},
            {"orange",     "$.59"},  {"watermelon", "$.39"},
            {"tangerine",  "$1.09"}, {"cherry",     "$.79"},
            {"banana",     "$.29"},  {"lime",       "$.33"},
            {"grapefruit", "$.69"},  {"grapes",     "$.49"},
         }, headers);
      
}
class SwingApp extends WindowAdapter {
   private SwingApp() {} // Can't instantiate this class

   public static void launch(final JFrame f, String title,
                       final int x, final int y, 
                       final int w, int h) {
      launch(f,title,x,y,w,h,null);   
   }
   public static void launch(final JFrame f, String title,
                       final int x, final int y, 
                       final int w, int h,
                       String propertiesFilename) {
      statusArea.setBorder(BorderFactory.createEtchedBorder());
      statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
      statusArea.add(status);
      status.setHorizontalAlignment(JLabel.LEFT);

      if(propertiesFilename != null) {
         resources = ResourceBundle.getBundle(
                  propertiesFilename, Locale.getDefault());
      }

      f.setTitle(title);
      f.setBounds(x,y,w,h);
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.setVisible(true);

   }
   static public JPanel getStatusArea() {
      return statusArea;
   }
   static public void showStatus(String s) {
      status.setText(s);
   }
   static Object getResource(String key) {
      if(resources != null) {
         return resources.getString(key);
      }
      return null;
   }
   static private JPanel statusArea = new JPanel();
   static private JLabel status = new JLabel(" ");
   static private ResourceBundle resources;
}
